package com.fingard.net.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;

import com.fingard.net.ConnState;
import com.fingard.net.listener.HttpReceiver;
import com.fingard.text.UrlHelper;

import com.fingard.FGBiz;

public class BizHttpClient {
	private String url = "";
	
	public String domain;
	public int port;
	
	private boolean isHttps;
	
	private String defCharest;
	private HashMap<String, String> reqProperties;
	public BizHttpClient(String pUrl, String p_charset){
		url = pUrl.trim();
		if(url.toLowerCase().startsWith("https")){
			isHttps = true;
		}else{
			isHttps = false;
		}
		defCharest = p_charset;
		reqProperties = new HashMap<String, String>();
		String[] ipPort = UrlHelper.pickupIpAndPort(url);
		domain = ipPort[0];
		port = Integer.parseInt(ipPort[1]);
	}
	
	public void setReqProperty(String pKey, String pVal){
		reqProperties.put(pKey, pVal);
	}
	
	/**接收字节超时时间，单位：毫秒，默认100000毫秒=100秒*/
	public int timeoutMil = 100000;
	
	/**连接超时时间，单位：毫秒，默认10000毫秒=10秒*/
	public int timeoutConn = 10000;
	
	public HttpReceiver post(byte[] pBodyBytes) throws Exception{
		//POST /notify HTTP/1.1
		StringBuilder sbReq = new StringBuilder();
		String page = UrlHelper.getPage(url);
		sbReq.append("POST " + page + " HTTP/1.1\r\n");
		sbReq.append("Host: "+domain+":"+port+"\r\n");
		Iterator<Map.Entry<String, String>> it = reqProperties.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, String> entry = it.next();
			sbReq.append(entry.getKey() + ": " + entry.getValue() + "\r\n");
		}
		sbReq.append("Content-Length: "+String.valueOf(pBodyBytes.length)+"\r\n\r\n");
		byte[] headBytes = sbReq.toString().getBytes(defCharest);
		
		if(isHttps){
			return postBytes(headBytes, pBodyBytes, true);
		}else{
			return postBytes(headBytes, pBodyBytes, false);
		}
	}

	//public String retHeadStr = "";
	private HttpReceiver postBytes(byte[] pHeadBytes, byte[] pBodyBytes, boolean pIsSsl) throws Exception{
		//String[] retStr = new String[]{"",""};
		HttpReceiver retReceiver = null;
		Socket socket = null;
		SSLSocket socket2 = null;
		try {
			if(pIsSsl){
				
				SSLContext context = SSLContext.getInstance("SSL");
				context.init(null, new TrustManager[]{new TrustManager()}, new SecureRandom());
				socket2 = (SSLSocket) context.getSocketFactory().createSocket();
				socket2.connect(new InetSocketAddress(domain, port), timeoutConn);
				socket2.startHandshake();
				socket = socket2;
				
			}else{
				socket = new Socket();
				socket.connect(new InetSocketAddress(domain, port), timeoutConn);
			}
			socket.setSoTimeout(timeoutMil);//180000
			retReceiver = new HttpReceiver(socket, defCharest);
			retReceiver.contentStartIndex = -1;
		}catch (Exception e) {
			if(retReceiver == null){
				retReceiver = new HttpReceiver(null, defCharest);
			}
			if(socket2!=null){
				socket2.close();
			}else if(socket!=null){
				socket.close();
			}
			retReceiver.connState = ConnState.FAIL;
			retReceiver.connMsg = e.getMessage();
			return retReceiver;
		}
		OutputStream tmpOutput = null;
		InputStream tmpInput = null;
		try {
			tmpOutput = socket.getOutputStream();
			if(pHeadBytes != null){
				tmpOutput.write(pHeadBytes);
			}
			tmpOutput.write(pBodyBytes);
			tmpOutput.flush();
			tmpInput = socket.getInputStream();
			
			retReceiver.recBytes = new byte[2048];//2K
			int tmpOffSet = 0;
            int idxLastCrlf = 0;
            //String httpMethod = "";
            byte tmpByteCr = "\r".getBytes(retReceiver.initCharset)[0];
            byte tmpByteLf = "\n".getBytes(retReceiver.initCharset)[0];
			//int stepChunkedLen = -1;//如果是TRANSFER-ENCODING:chunked，记录每次的长度
			while(!retReceiver.isCompleted){
				int tmpReadLen = tmpInput.read(retReceiver.recBytes, tmpOffSet, retReceiver.recBytes.length - tmpOffSet);
				if(tmpReadLen<=0){
					break;
				}
				retReceiver.readedLength = retReceiver.readedLength + tmpReadLen;
                if (retReceiver.contentStartIndex == -1) {
                    for (int i = idxLastCrlf; i < retReceiver.readedLength; i++) {
                        if (retReceiver.recBytes[i] == tmpByteLf) {//是\n
                        	int tmpEndCount = i - idxLastCrlf;
                            if (i > 1 && retReceiver.recBytes[i - 1] == tmpByteCr){// 前一个字符是\r
                            	tmpEndCount--;
                            }
                            String tmpHeadStr = new String(retReceiver.recBytes, idxLastCrlf, tmpEndCount, retReceiver.initCharset);
                            String tmpKey = "";
                            String tmpValue = "";
                            
                            int idx1 = tmpHeadStr.indexOf(":");
                            if(idx1>0){
                            	tmpKey = tmpHeadStr.substring(0,idx1).toLowerCase().trim();
                            	tmpValue = tmpHeadStr.substring(idx1+1).toLowerCase().trim();
                            }else{
                            	tmpKey = tmpHeadStr.toLowerCase().trim();
                            }
                            retReceiver.headKV.put(tmpKey, tmpValue);
                            if ("content-length".equals(tmpKey)) {
                            	retReceiver.contentLength = Integer.valueOf(tmpValue);
                            }else if("transfer-encoding".equals(tmpKey)){
                            	if("chunked".equals(tmpValue)){
                            		isTransferChunked = true;
                            	}
                            }
                            idxLastCrlf = i + 1;

                            if ((i < tmpReadLen - 1 && retReceiver.recBytes[i + 1] == tmpByteCr) ||
                                    (i < tmpReadLen - 2 && retReceiver.recBytes[i + 2] == tmpByteLf)) {
                            	retReceiver.contentStartIndex = i+1;
                                if(retReceiver.recBytes[i + 2] == tmpByteLf){
                                	retReceiver.contentStartIndex = i+3;
                                }
                                break;
                            }
                        }
                    }
                }
                tmpOffSet += tmpReadLen;
                
                if (retReceiver.contentLength > 0 && retReceiver.contentStartIndex > 0) {
                    if (retReceiver.recBytes.length < retReceiver.contentLength + retReceiver.contentStartIndex) {
                        byte[] tmpUnionInfo = new byte[retReceiver.contentLength + retReceiver.contentStartIndex];//一次性分配内存
                        System.arraycopy(retReceiver.recBytes, 0, tmpUnionInfo, 0, tmpOffSet);
                        retReceiver.recBytes = null;
                        retReceiver.recBytes = tmpUnionInfo;
                    }

                    int tmpToReadLen = retReceiver.contentLength + retReceiver.contentStartIndex - tmpOffSet;
                    if (tmpToReadLen <= 0) {
                    	retReceiver.isCompleted = true;
                        break;
                    }
                }else if(retReceiver.readedLength>0&& (retReceiver.readedLength<20 || retReceiver.contentStartIndex<0)){
                	continue;
                }  else {
                    break;
                }
                if(isTransferChunked){//TRANSFER-ENCODING:chunked
                	//chunked
                }
                /*
				if(isTransferChunked){//TRANSFER-ENCODING:chunked
					if(retReceiver.contentStartIndex>0){
						if(stepChunkedLen<0){
							
						}
					}
					//p_receiver.recBytes[i + 2] == tmpHeadCut2
				}else{
					if (retReceiver.contentLength > 0)
	                {
	                    if (retReceiver.recBytes.length < retReceiver.contentLength + retReceiver.contentStartIndex)
	                    {
	                        byte[] tmpUnionInfo = new byte[retReceiver.contentLength + retReceiver.contentStartIndex];//一次性分配内存
	        				System.arraycopy(retReceiver.recBytes, 0, tmpUnionInfo, 0, tmpOffSet);
	        				retReceiver.recBytes = null;
	        				retReceiver.recBytes = tmpUnionInfo;
	                    }
	                    
	                    int tmpToReadLen = retReceiver.contentLength + retReceiver.contentStartIndex - tmpOffSet;
	                    if (tmpToReadLen <= 0)
	                    {
	                    	retReceiver.isCompleted = true;
	                    	break;
	                    }
	                }
					else if(retReceiver.recBytes.length - tmpOffSet < 1024){//扩展
						byte[] tmpUnionInfo2 = new byte[tmpOffSet + 20480];
						System.arraycopy(retReceiver.recBytes, 0, tmpUnionInfo2, 0, tmpOffSet);
						retReceiver.recBytes = null;
						retReceiver.recBytes = tmpUnionInfo2;
					}
				}*/
			}
			tmpOutput.close();
			tmpOutput = null;
			tmpInput.close();
			tmpInput = null;
		}
		catch (IOException e) {
			FGBiz.limitMsg.exception("", e);
			retReceiver.connMsg = e.getMessage();
		}finally{
			if(tmpOutput != null){
				tmpOutput.close();
			}
			if(tmpInput != null){
				tmpInput.close();
			}
			if(socket != null){
				socket.close();
			}
		}
		return retReceiver;
	}
	private boolean isTransferChunked = false;
	/*
	private static byte tmpByteLt = '<';//"<".getBytes("gbk")[0];
    private static byte tmpHeadCut1 = '\r';//"\\r".getBytes("gbk")[0];
    private static byte tmpHeadCut2 = '\n';//"\\n".getBytes("gbk")[0];
    
    
    
    public void getContentLength(TcpReceiver p_receiver) throws Exception {
        if (p_receiver.contentLength == -1) {
        	for (int i = p_receiver.readHeadStartIndex; i < p_receiver.readedLength; i++) {
            	if (p_receiver.recBytes[i] == tmpHeadCut2){// 是\n
                    int tmpEndCount = i - p_receiver.readHeadStartIndex;
                    if (i > 1 && p_receiver.recBytes[i - 1] == tmpHeadCut1){// 前一个字符是\r
                    	tmpEndCount--;
                    }
                    String tmpHeadKeyValue = new String(p_receiver.recBytes, p_receiver.readHeadStartIndex, tmpEndCount, defCharest);
                    String tmpKey = "";
                    String tmpValue = "";
                    
                    int idx1 = tmpHeadKeyValue.indexOf(":");
                    if(idx1>0){
                    	tmpKey = tmpHeadKeyValue.substring(0,idx1).toLowerCase();
                    	tmpValue = tmpHeadKeyValue.substring(idx1+1).toLowerCase();
                    }
                    
                    if (tmpKey.equals("content-length")){
                    	p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                    }else if(tmpKey.equals("transfer-encoding")){
                    	if("chunked".equals(tmpValue.trim().toLowerCase())){
                    		isTransferChunked = true;
                    	}
                    }
                    p_receiver.readHeadStartIndex = i + 1;
                    
                    if (p_receiver.readedLength > (i + 1) && p_receiver.recBytes[i + 1] == tmpHeadCut2){
                    	p_receiver.contentStartIndex = i+2;
                    	retHeadStr = new String(p_receiver.recBytes, 0, p_receiver.contentStartIndex, defCharest);
                        break;
                    }else if (p_receiver.readedLength > (i + 2) && p_receiver.recBytes[i + 2] == tmpHeadCut2){
                    	p_receiver.contentStartIndex = i+3;
                    	retHeadStr = new String(p_receiver.recBytes, 0, p_receiver.contentStartIndex, defCharest);
                        break;
                    }
                }else if (p_receiver.recBytes[i] == tmpByteLt){//是<
                	p_receiver.contentStartIndex = i;
                    break;
                }
            }
        	
        }
    }*/
}
